package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.cart.service.CartInfoSyncService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.produck.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: Mr.Cao
 * @DateTime: 2021/10/11 20:03
 * BMW F750GS
 **/
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper,CartInfo> implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private CartInfoSyncService cartInfoSyncService;

    //加入购物车
    @Override
    public CartInfo addToCart(Long skuId, Integer skuNum,String userId) {

        //（重要）1:保存购物车到Redis缓存中
        //Hash   Map h   h.put(hk(手机ID),hv(手机))  h:userId
        // h  user:3:cart   真实用户的购物车
        // h  user:abgsrdffgrfsdgrfg:cart  临时用户的购物车
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX; //user:id值:cart
        //1.1 查询缓存中的购物车
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        if (null != cartInfo) {
            //此用户在之前已经加入过此商品  本次追加数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //（不重要） 2:保存购物车到DB中   2写
            cartInfoSyncService.updateCartInfo(cartInfo);//800ms   异步
        } else {
            //此用户在之前没有添加过此商品  添加此商品
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);//从缓存查询商品信息
            BigDecimal price = productFeignClient.getPrice(skuId);//获取实时价格
            cartInfo.setCartPrice(price);//实时价格
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            //（不重要） 2:保存购物车到DB中   2写
            cartInfoSyncService.insertCartInfo(cartInfo);//800ms   异步
        }
        //走了加入购物车之后 必须勾选上
        cartInfo.setIsChecked(1);

        //保存回缓存   1写
        redisTemplate.opsForHash().put(cartHKey, skuId.toString(), cartInfo);//200ms
        return cartInfo;
    }
    /**
     * 添加完购物项后,跳转到购物车页面,并回显数据
     * */
    @Override
    public CartInfo toCart(Long skuId, String userId) {
        //用户购物车在redis缓存中存的map类型的key值
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //从redis缓存中宣勋
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        return cartInfo;
    }
    /**
     * 跳转到购物车页面,查询所有购物项
     * */
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //当前用户：
        // 如果登录了应该查询（真实用户的 + 临时用户的）  临时用户的购物车清空
        // 如果未登录是临时用户的购物车集合
        //1:判断用户是否登录
        if (!StringUtils.isEmpty(userId)){
            if (!StringUtils.isEmpty(userTempId)) {
                //用户登录了,且有临时用户Id,需要将临时的和真实用户的购物项进行合并
                //大合并
                return mergeCartInfoList(userId,userTempId);
            }else {
                //没有临时用户Id 只有真实的用户Id ,
                // 直接从redis缓存中根据真实用户Id 查询购物项
                return this.getCartInfoList(userId);
            }
        }else {
            //用户没有登录,此时是有临时用户的
            //未登录  没有真实用户的ID
            if(!StringUtils.isEmpty(userTempId)){
                //临时用户ID是有的
                return getCartInfoList(userTempId);
            }
        }
        return null;
    }
    //数据大合并,将临时用户的购物项和真实用户Id的购物项目进行合并
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //1:获取购物车集合（真实用户ID ）
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        //2:获取购物车集合（临时用户ID ）
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);

        //开始进行合并
        //先判断真实用户是否有购物项
        if (!CollectionUtils.isEmpty(cartInfoListByUserId)) {
            //真实用户有购物项
            //将真实用户的购物项转换为map ,map的key值为商品的id(skuId),value值为 cartInfo
            Map<String, CartInfo> cartInfoMap = cartInfoListByUserId.stream().collect(Collectors.toMap(
                    cartInfo -> cartInfo.getSkuId().toString(),
                    cartInfo -> cartInfo
            ));
            //遍历临时购物车集合
            for (CartInfo cartInfoByTempId : cartInfoListByUserTempId) {
                //根据遍历出来的cartInfoByTempId的商品Id(skuId)获取cartInfo
                CartInfo cartInfoByUserId = cartInfoMap.get(cartInfoByTempId.getSkuId().toString());
                if (cartInfoByUserId!=null){
                    //说明有相同的购物项,进行购物项的合并, 即 追加数量
                    cartInfoByUserId.setSkuNum(cartInfoByTempId.getSkuNum()+cartInfoByUserId.getSkuNum());
                    //设置默认为选中状态
                    cartInfoByUserId.setIsChecked(1);
                }else {
                    //说明没有相同的购物项,进行增加购物项
                    //对临时用户的购物项这是真实用户的Id
                    cartInfoByTempId.setUserId(userId);
                    //将临时用户的购物项追加到真实用户的购物项中的 key值为 skuId value值为cartInfo
                    cartInfoMap.put(cartInfoByTempId.getSkuId().toString(),cartInfoByTempId);
                }
            }
            //进行统一处理
            //删除缓存中临时用书的数据
            //cart redis缓存的key
            String cartHKeyUserTempId = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
            //redisTemplate.opsForHash().delete(cartHKeyUserTempId,"7");
            redisTemplate.delete(cartHKeyUserTempId);
            //删除数据库中临时用户的数据
            cartInfoMapper.delete(new QueryWrapper<CartInfo>().eq("user_id",userTempId));

            //将合并后的真实用的购物项集合添加进缓存中和数据库中
            String cartHKeyUserId = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
            redisTemplate.opsForHash().putAll(cartHKeyUserId,cartInfoMap);//添加进缓存
            //将合并后的真是用户的购物项转换成List集合
            List<CartInfo> cartInfoList = new ArrayList<CartInfo>(cartInfoMap.values());
            this.saveBatch(cartInfoList);//添加进数据库

            //然后返回真实用户的购物项
            return cartInfoList;
        }else {
            //真实用户没有购物项
            //判断临时用户是否有购物项
            if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)){
                //临时用户有购物项
                //真实用户的购物车集合 但是临时用户有, 返回临时用户的购物车集合
                return cartInfoListByUserTempId;
            }else {
                //真实用户没有购物项,且临时用户没有购物项,则直接返回null值
                return null;
            }
        }
    }

    //获取购物车集合 根据用户的ID
    private List<CartInfo> getCartInfoList(String userId) {
        //cart redis缓存的key
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //从redis缓存中获取
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //遍历集合,设置实时的价格
       cartInfoList.stream().forEach(cartInfo -> {
           //远程调用从数据库查询实时的价格
           BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
           cartInfo.setSkuPrice(price);
       });
        //TODO 排序  ID  时间
        //返回值购物车集合
        return cartInfoList;
    }
    /**
     * //去结算页面显示,已经选中的商品
     * */
    @Override
    public List<CartInfo> getCartInfoListByChecked(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //从redis缓存中获取用户购物车
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //通过stream流 过滤集合,选出被选中的
        List<CartInfo> list = cartInfoList.stream().filter(cartInfo -> 1 == cartInfo.getIsChecked())
                .peek(cartInfo -> { //peek  约等 foreach  区别：foreach结束   peek后面还可以继续filter sorted
                    //设置实时价格
                    BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
                    cartInfo.setSkuPrice(price);
                })
                .collect(Collectors.toList());
        return list;
    }
}
